package com.gaofans.nrpc.example;

import com.gaofans.nrpc.client.bootstrap.ChannelManager;
import com.gaofans.nrpc.client.bootstrap.ChannelManagerBuilder;
import com.gaofans.nrpc.client.proxy.ServiceProxyBuilder;
import com.gaofans.nrpc.client.route.LoadBalance;
import com.gaofans.nrpc.client.route.ServiceInstance;
import com.gaofans.nrpc.client.route.impl.LoadBalanceRouter;
import com.gaofans.nrpc.client.route.impl.LoadBalanceRouterPredicate;
import com.gaofans.nrpc.common.id.SnowFlakeGenerator;
import com.gaofans.nrpc.common.processor.ServiceAuthority;
import com.gaofans.nrpc.example.dict.Dict;
import com.gaofans.nrpc.example.dict.DictService;
import io.netty.handler.ssl.SslContext;
import io.netty.handler.ssl.SslContextBuilder;

import javax.net.ssl.KeyManagerFactory;
import javax.net.ssl.SSLException;
import javax.net.ssl.TrustManagerFactory;
import java.io.FileInputStream;
import java.io.InputStream;
import java.net.URI;
import java.security.KeyStore;

public class ClientApplication {

    public static void main(String[] args) throws Exception {
        try {
            DictService service = buildClient();
            service.addDict("1","d1","tips","10").doOnSuccess(unused -> {
                service.selectByCode("1").subscribe(l -> {
                    for (Dict dict : l) {
                        System.out.println(dict);
                    }
                });
            }).subscribe();

        } catch (Exception e) {
            e.printStackTrace();
        }
        Thread.currentThread().join();
    }

    public static DictService buildClient() throws Exception {

        ChannelManagerBuilder managerBuilder = new ChannelManagerBuilder();
        ChannelManager manager = managerBuilder
                .registerRouter(router())
                .idGenerator(new SnowFlakeGenerator(31,31))
                .sslContext(buildClientSSL())
                .addFilter((request, chain) -> {
                    request.putHeader("token","123456");
                    return chain.doFilter(request);
                })
                .build();
        ServiceProxyBuilder<DictService> proxyBuilder = new ServiceProxyBuilder<>(manager);
        proxyBuilder.setServiceClass(DictService.class);
        proxyBuilder.setUri(new URI("lb://remote"));
        return proxyBuilder.build();

    }

    public static LoadBalanceRouter router(){
        LoadBalanceRouterPredicate predicate = new LoadBalanceRouterPredicate();
        MockServiceStore store = new MockServiceStore();
        store.add("remote",new ServiceInstance("remote","remote-1",new ServiceAuthority("localhost",8080)));
        store.add("remote",new ServiceInstance("remote","remote-2",new ServiceAuthority("localhost",8081)));
        store.add("remote",new ServiceInstance("remote","remote-3",new ServiceAuthority("localhost",8082)));
        store.add("remote",new ServiceInstance("remote","remote-4",new ServiceAuthority("localhost",8083)));
        return new LoadBalanceRouter(12,predicate,store, LoadBalance.getInstance());
    }

    public static SslContext buildClientSSL() throws SSLException {
        SslContextBuilder clientSSlBuilder = SslContextBuilder.forClient();
        String clentPk = "D:\\git\\nrpc\\example\\target\\classes\\cChat.jks";
        return SslContextBuilder.forClient().keyManager(km(clentPk,"cNetty")).trustManager(tm(clentPk,"cNetty")).build();
    }

    public static SslContext buildServerSSL() throws SSLException {
        SslContextBuilder clientSSlBuilder = SslContextBuilder.forClient();
        String serverPk = "D:\\git\\nrpc\\example\\target\\classes\\sChat.jks";
        return SslContextBuilder.forServer(km(serverPk,"sNetty")).trustManager(tm(serverPk,"sNetty")).build();
    }

    public static KeyManagerFactory km(String pkPath,String password){
        try (InputStream in = new FileInputStream(pkPath)){
            //密钥管理器
            KeyStore ks = KeyStore.getInstance("JKS");
            ks.load(in, password.toCharArray());
            KeyManagerFactory kmf = KeyManagerFactory.getInstance("SunX509");
            kmf.init(ks, password.toCharArray());
            return kmf;
        } catch (Exception e) {
            throw new RuntimeException(e);
        }

    }

    public static TrustManagerFactory tm(String caPath,String password){
        try (InputStream in = new FileInputStream(caPath)){
            //信任库
            KeyStore tks = KeyStore.getInstance("JKS");
            tks.load(in, password.toCharArray());
            TrustManagerFactory tf = TrustManagerFactory.getInstance("SunX509");
            tf.init(tks);
            return tf;
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }
}
